package com.zhoug.player.exoplayer.v2;

import android.content.Context;

import java.util.Map;

import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.datasource.DefaultHttpDataSource;
import androidx.media3.datasource.HttpDataSource;
import androidx.media3.exoplayer.hls.DefaultHlsExtractorFactory;
import androidx.media3.exoplayer.hls.HlsMediaSource;
import androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory;

/**
 * @author: zhoug
 * @since: 2025-06-25
 */
@UnstableApi
public class ZExoFactory {

    private ZExoFactory() {
    }

    /**
     * 从网络读取数据工厂
     */
    public static final class DefaultHttpDataSourceFactoryBuilder {
        /**
         * 连接超时
         */
        private int connectTimeoutMs = 5_000;
        /**
         * 读取超时
         */
        private int readTimeoutMs = 15_000;
        /**
         * 跨协议请求重定向
         */
        private boolean allowCrossProtocolRedirects = true;
        /**
         * 设置当我们对POST请求进行HTTP 302重定向时，是否应保留POST方法和主体
         */
        private boolean keepPostFor302Redirects = true;
        /**
         * 设置是否应强制跨协议重定向遵循原始协议
         */
        private boolean crossProtocolRedirectsForceOriginal = false;
        /**
         * 要使用的用户代理
         */
        private String userAgent ;
        /**
         * 请求参数
         */
        private Map<String, String> defaultRequestProperties;



        /**
         * 连接超时
         *
         * @param connectTimeoutMs 连接超时 单位毫秒
         */
        public DefaultHttpDataSourceFactoryBuilder setConnectTimeoutMs(int connectTimeoutMs) {
            this.connectTimeoutMs = connectTimeoutMs;
            return this;
        }

        /**
         * 读取超时
         *
         * @param readTimeoutMs 读取超时 单位毫秒
         */
        public DefaultHttpDataSourceFactoryBuilder setReadTimeoutMs(int readTimeoutMs) {
            this.readTimeoutMs = readTimeoutMs;
            return this;
        }

        /**
         * 跨协议请求重定向
         *
         * @param allowCrossProtocolRedirects 跨协议请求重定向
         */
        public DefaultHttpDataSourceFactoryBuilder setAllowCrossProtocolRedirects(boolean allowCrossProtocolRedirects) {
            this.allowCrossProtocolRedirects = allowCrossProtocolRedirects;
            return this;
        }

        /**
         * 设置当我们对POST请求进行HTTP 302重定向时，是否应保留POST方法和主体
         *
         * @param keepPostFor302Redirects 是否应保留POST方法和主体
         */
        public DefaultHttpDataSourceFactoryBuilder setKeepPostFor302Redirects(boolean keepPostFor302Redirects) {
            this.keepPostFor302Redirects = keepPostFor302Redirects;
            return this;
        }

        /**
         * 设置是否应强制跨协议重定向遵循原始协议
         *
         * @param crossProtocolRedirectsForceOriginal 强制跨协议重定向遵循原始协议
         */
        public void setCrossProtocolRedirectsForceOriginal(boolean crossProtocolRedirectsForceOriginal) {
            this.crossProtocolRedirectsForceOriginal = crossProtocolRedirectsForceOriginal;
        }

        /**
         * 要使用的用户代理
         * 默认值为null，这将导致使用底层平台的默认用户代理
         *
         * @param userAgent 用户代理
         */
        public DefaultHttpDataSourceFactoryBuilder setUserAgent(String userAgent) {
            this.userAgent = userAgent;
            return this;
        }

        /**
         * 请求参数
         *
         * @param defaultRequestProperties 请求参数
         */
        public DefaultHttpDataSourceFactoryBuilder setDefaultRequestProperties(Map<String, String> defaultRequestProperties) {
            this.defaultRequestProperties = defaultRequestProperties;
            return this;
        }

        /**
         * 创建工厂
         *
         * @return
         */
        public DefaultHttpDataSource.Factory build() {
            //从网络读取数据工厂
            DefaultHttpDataSource.Factory factory = new DefaultHttpDataSource.Factory();
            factory.setConnectTimeoutMs(connectTimeoutMs)//连接超时
                    .setReadTimeoutMs(readTimeoutMs)//读取超时
                    .setAllowCrossProtocolRedirects(allowCrossProtocolRedirects)//跨协议重定向
                    .setKeepPostFor302Redirects(keepPostFor302Redirects)//设置当我们对POST请求进行HTTP 302重定向时，是否应保留POST方法和主体
                    .setUserAgent(userAgent);
            if (defaultRequestProperties != null) {
                factory.setDefaultRequestProperties(defaultRequestProperties);
            }
            if (!allowCrossProtocolRedirects) {
                factory.setCrossProtocolRedirectsForceOriginal(crossProtocolRedirectsForceOriginal);
            }
            factory.setTransferListener(new ZDefaultTransferListener());
            return factory;
        }

    }

    /**
     * 支持多个URI方案的DataSource。支持的方案包括
     * file: eg file:///path/to/media/media.mp4  /path/to/media/media.mp4
     * asset: eg  asset:///media.mp4
     * rawresource: eg rawresource:///resourceId
     * android.resource: eg android.resource://resourceType/resourceName
     * content: eg content://authority/path/123
     * rtmp:
     * data: 用于解析RFC 2397中定义的URI中内联的数据
     * udp: eg  udp://something.com/media
     * http(s):  eg https://www.something.com/media.mp4
     */
    public static final class DefaultDataSourceFactoryBuilder {
        public DefaultDataSource.Factory build(Context context, DataSource.Factory baseDataSourceFactory) {
            return new DefaultDataSource.Factory(context, baseDataSourceFactory);
        }
    }


    /**
     * HLS数据源工厂
     */
    public static final class HlsMediaSourceFactoryBuilder {
        /**
         * 禁用分块准备（默认true） 强制检查每个片段
         */
        private boolean allowChunklessPreparation=true;
        /**
         * 某些MPEG-TS文件不包含访问单元分隔符（AUD）。默认情况下，ExoPlayer依靠AUD来便宜地检测帧边界。
         * 同样，某些MPEG-TS文件不包含IDR关键帧。默认情况下，这些是ExoPlayer考虑的唯一关键帧类型。
         * 当被要求播放缺少AUD或IDR关键帧的MPEG-TS文件时，ExoPlayer缓冲会报错
         * 如果需要播放此类文件 设置为true
         * FLAG_ALLOW_NON_IDR_KEYFRAMES
         * FLAG_DETECT_ACCESS_UNITS
         */
        private boolean detectAccessUnits=false;

        /**
         * 禁用分块准备（默认true） 强制检查每个片段
         * @param allowChunklessPreparation 默认false
         */
        public HlsMediaSourceFactoryBuilder setAllowChunklessPreparation(boolean allowChunklessPreparation) {
            this.allowChunklessPreparation = allowChunklessPreparation;
            return this;
        }

        /**
         * 某些MPEG-TS文件不包含访问单元分隔符（AUD）。默认情况下，ExoPlayer依靠AUD来便宜地检测帧边界。
         * 同样，某些MPEG-TS文件不包含IDR关键帧。默认情况下，这些是ExoPlayer考虑的唯一关键帧类型。
         * 当被要求播放缺少AUD或IDR关键帧的MPEG-TS文件时，ExoPlayer缓冲会报错
         * 如果需要播放此类文件 设置为true
         * FLAG_ALLOW_NON_IDR_KEYFRAMES
         * FLAG_DETECT_ACCESS_UNITS
         * @param detectAccessUnits 默认false
         */
        public HlsMediaSourceFactoryBuilder setDetectAccessUnits(boolean detectAccessUnits) {
            this.detectAccessUnits = detectAccessUnits;
            return this;
        }


        public HlsMediaSource.Factory create(Context context, HttpDataSource.Factory dataSourceFactory) {
            //支持多个URI方案的DataSource。支持的方案包括
            DefaultDataSource.Factory defaultDataSourceFactory = new DefaultDataSourceFactoryBuilder()
                    .build(context,dataSourceFactory);
            HlsMediaSource.Factory factory = new HlsMediaSource.Factory(defaultDataSourceFactory);
            factory.setAllowChunklessPreparation(allowChunklessPreparation);// 强制检查每个片段
            //HLS片段提取工厂
            DefaultHlsExtractorFactory defaultHlsExtractorFactory;
            if (detectAccessUnits) {
                defaultHlsExtractorFactory = new DefaultHlsExtractorFactory(DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS, false);
            } else {
                defaultHlsExtractorFactory = new DefaultHlsExtractorFactory();
            }
            factory.setExtractorFactory(defaultHlsExtractorFactory);
            return factory;
        }
    }



}
